﻿using Mapster;
using Microsoft.AspNetCore.Identity;
using Microsoft.AspNetCore.Mvc;
using My.Admin.Dto.User;
using My.Admin.Enum;
using My.Admin.Model.System;
using My.Admin.Repository;
using My.Admin.Service.System.IService;
using My.Core.CustomException;
using My.Core.Enums;
using System.ComponentModel;

namespace My.Admin.Service.System
{
	public class SysOrgService : BaseService<SysOrg>, ISysOrgService
	{
		private readonly UserManager _userManager;
		private readonly ISysUserRoleService _sysUserRoleService;

		public SysOrgService(UserManager userManager, ISysUserRoleService sysUserRoleService)
		{
			_userManager = userManager;
			_sysUserRoleService = sysUserRoleService;
		}

		/// <summary>
		/// 获取机构列表
		/// </summary>
		/// <returns></returns>
		public async Task<List<SysOrg>> GetList(OrgInput input)
		{
			// 获取拥有的机构Id集合
			var userOrgIdList = await GetUserOrgIdList();

			var iSugarQueryable = AsQueryable().OrderBy(u => u.OrderNo);

			// 带条件筛选时返回列表数据
			if (!string.IsNullOrWhiteSpace(input.Name) || !string.IsNullOrWhiteSpace(input.Code) || !string.IsNullOrWhiteSpace(input.Type))
			{
				return await iSugarQueryable.WhereIF(userOrgIdList.Count > 0, u => userOrgIdList.Contains(u.Id))
					.WhereIF(!string.IsNullOrWhiteSpace(input.Name), u => u.Name.Contains(input.Name))
					.WhereIF(!string.IsNullOrWhiteSpace(input.Code), u => u.Code == input.Code)
					.WhereIF(!string.IsNullOrWhiteSpace(input.Type), u => u.Type == input.Type)
					.ToListAsync();
			}

			var sysOrg = await GetSingleAsync(u => u.Id == input.Id);
			var orgTree = new List<SysOrg>();

			if (_userManager.SuperAdmin)
			{
				orgTree = await iSugarQueryable.ToTreeAsync(u => u.Children, u => u.Pid, sysOrg?.Pid);
			}
			else
			{
				orgTree = await iSugarQueryable.ToTreeAsync(u => u.Children, u => u.Pid, sysOrg?.Pid, userOrgIdList.Select(d => (object)d).ToArray());
				// 递归禁用没权限的机构（防止用户修改或创建无权的机构和用户）
				HandlerOrgTree(orgTree, userOrgIdList);
			}
			return orgTree;
		}

		/// <summary>
		/// 递归禁用没权限的机构
		/// </summary>
		/// <param name="orgTree"></param>
		/// <param name="userOrgIdList"></param>
		private void HandlerOrgTree(List<SysOrg> orgTree, List<long> userOrgIdList)
		{
			foreach (var org in orgTree)
			{
				org.Disabled = !userOrgIdList.Contains(org.Id); // 设置禁用/不可选择
				if (org.Children != null)
					HandlerOrgTree(org.Children, userOrgIdList);
			}
		}

		/// <summary>
		/// 获取机构Id集合
		/// </summary>
		/// <returns></returns>
		public async Task<List<long>> GetUserOrgIdList()
		{
			//return new List<long>();
			if (_userManager.SuperAdmin)
				return new List<long>();

			long userId = _userManager.UserId;

			// 角色机构集合
			var orgIdList = await GetUserRoleOrgIdList(userId);

			// 当前所属机构
			if (!orgIdList.Contains(_userManager.OrgId))
				orgIdList.Add(_userManager.OrgId);

			return orgIdList;
		}

		/// <summary>
		/// 获取用户角色机构Id集合
		/// </summary>
		/// <param name="userId"></param>
		/// <returns></returns>
		private async Task<List<long>> GetUserRoleOrgIdList(long userId)
		{
			var roleList = await _sysUserRoleService.GetUserRoleList(userId);
			if (roleList.Count < 1)
				return new List<long>(); // 空机构Id集合

			return await GetUserOrgIdList(roleList);
		}

		/// <summary>
		/// 根据角色Id集合获取机构Id集合
		/// </summary>
		/// <param name="roleList"></param>
		/// <returns></returns>
		private async Task<List<long>> GetUserOrgIdList(List<SysRole> roleList)
		{
			// 按最大范围策略设定(若同时拥有ALL和SELF权限，则结果ALL)
			int strongerDataScopeType = (int)DataScopeEnum.Self;

			// 角色集合拥有的数据范围
			var customDataScopeRoleIdList = new List<long>();
			if (roleList != null && roleList.Count > 0)
			{
				roleList.ForEach(u =>
				{
					if (u.DataScope == DataScopeEnum.Define)
					{
						customDataScopeRoleIdList.Add(u.Id);
						strongerDataScopeType = (int)u.DataScope; // 自定义数据权限时也要更新最大范围
					}
					else if ((int)u.DataScope <= strongerDataScopeType)
						strongerDataScopeType = (int)u.DataScope;
				});
			}

			// 根据数据范围获取机构集合
			var orgIdList = await GetOrgIdListByDataScope(strongerDataScopeType);

			// 并集机构集合
			return orgIdList;
		}

		/// <summary>
		/// 根据数据范围获取机构Id集合
		/// </summary>
		/// <param name="dataScope"></param>
		/// <returns></returns>
		private async Task<List<long>> GetOrgIdListByDataScope(int dataScope)
		{
			var orgId = _userManager.OrgId;
			var orgIdList = new List<long>();
			// 若数据范围是全部，则获取所有机构Id集合
			if (dataScope == (int)DataScopeEnum.All)
			{
				orgIdList = await AsQueryable().Select(u => u.Id).ToListAsync();
			}
			// 若数据范围是本部门及以下，则获取本节点和子节点集合
			else if (dataScope == (int)DataScopeEnum.DeptChild)
			{
				orgIdList = await GetChildIdListWithSelfById(orgId);
			}
			// 若数据范围是本部门不含子节点，则直接返回本部门
			else if (dataScope == (int)DataScopeEnum.Dept)
			{
				orgIdList.Add(orgId);
			}
			return orgIdList;
		}

		/// <summary>
		/// 增加机构
		/// </summary>
		/// <param name="input"></param>
		/// <returns></returns>
		public async Task<long> AddOrg(AddOrgInput input)
		{
			if (await IsAnyAsync(u => u.Name == input.Name && u.Code == input.Code))
				throw new CustomException(ResultCode.CUSTOM_ERROR, "已有相同组织机构,编码或名称相同", "已有相同组织机构,编码或名称相同");

			var newOrg = await AsInsertable(input.Adapt<SysOrg>()).ExecuteReturnEntityAsync();
			return newOrg.Id;
		}

		/// <summary>
		/// 更新机构
		/// </summary>
		/// <param name="input"></param>
		/// <returns></returns>
		public async Task UpdateOrg(UpdateOrgInput input)
		{

			if (input.Id == input.Pid)
				throw new CustomException(ResultCode.CUSTOM_ERROR, "当前机构Id不能与父机构Id相同", "当前机构Id不能与父机构Id相同");
			if (await IsAnyAsync(u => u.Name == input.Name && u.Code == input.Code && u.Id != input.Id))
				throw new CustomException(ResultCode.CUSTOM_ERROR, "已有相同组织机构,编码或名称相同", "已有相同组织机构,编码或名称相同");

			// 父Id不能为自己的子节点
			var childIdList = await GetChildIdListWithSelfById(input.Id);
			if (childIdList.Contains(input.Pid))
				throw new CustomException(ResultCode.CUSTOM_ERROR, "当前机构Id不能与父机构Id相同", "当前机构Id不能与父机构Id相同");

			await AsUpdateable(input.Adapt<SysOrg>()).IgnoreColumns(true).ExecuteCommandAsync();
		}

		/// <summary>
		/// 删除机构
		/// </summary>
		/// <param name="input"></param>
		/// <returns></returns>
		public async Task DeleteOrg(DeleteOrgInput input)
		{
			var sysOrg = await GetFirstAsync(u => u.Id == input.Id) ?? throw new CustomException(ResultCode.CUSTOM_ERROR, "记录不存在", "记录不存在");

			// 若机构有用户则禁止删除
			var orgHasEmp = await ChangeRepository<BaseRepository<SysUser>>()
				.IsAnyAsync(u => u.OrgId == input.Id);
			if (orgHasEmp)
				throw new CustomException(ResultCode.CUSTOM_ERROR, "该机构下有用户禁止删除", "该机构下有用户禁止删除");

			// 若子机构有用户则禁止删除
			var childOrgTreeList = await AsQueryable().ToChildListAsync(u => u.Pid, input.Id, true);
			var childOrgIdList = childOrgTreeList.Select(u => u.Id).ToList();

			// 若子机构有用户则禁止删除
			var cOrgHasEmp = await ChangeRepository<BaseRepository<SysUser>>()
				.IsAnyAsync(u => childOrgIdList.Contains(u.OrgId));
			if (cOrgHasEmp)
				throw new CustomException(ResultCode.CUSTOM_ERROR, "下级机构下有用户禁止删除", "下级机构下有用户禁止删除");

			// 级联删除机构子节点
			await DeleteAsync(u => childOrgIdList.Contains(u.Id));
		}

		/// <summary>
		/// 根据节点Id获取子节点Id集合(包含自己)
		/// </summary>
		/// <param name="pid"></param>
		/// <returns></returns>
		public async Task<List<long>> GetChildIdListWithSelfById(long pid)
		{
			var orgTreeList = await AsQueryable().ToChildListAsync(u => u.Pid, pid, true);
			return orgTreeList.Select(u => u.Id).ToList();
		}
	}
}
